--[[

Copyright (c) 2011-2014 chukong-inc.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

]]

--[[--

针对 cc.Node 的扩展

]]

local c = cc
local Node = c.Node

-- touch
c.TouchesAllAtOnce              = cc.TOUCHES_ALL_AT_ONCE
c.TouchesOneByOne               = cc.TOUCHES_ONE_BY_ONE
c.TOUCH_MODE_ALL_AT_ONCE        = c.TouchesAllAtOnce
c.TOUCH_MODE_ONE_BY_ONE         = c.TouchesOneByOne

local function isPointIn( rc, pt )
    local rect = cc.rect(rc.x, rc.y, rc.width, rc.height)
    return cc.rectContainsPoint(rect, pt)
end

function Node:align(anchorPoint, x, y)
    self:setAnchorPoint(display.ANCHOR_POINTS[anchorPoint])
    if x and y then self:setPosition(x, y) end
    return self
end

function Node:schedule(callback, interval)
    local seq = transition.sequence({
        cc.DelayTime:create(interval),
        cc.CallFunc:create(callback),
    })
    local action = cc.RepeatForever:create(seq)
    self:runAction(action)
    return action
end

function Node:performWithDelay(callback, delay)
    local action = transition.sequence({
        cc.DelayTime:create(delay),
        cc.CallFunc:create(callback),
    })
    self:runAction(action)
    return action
end

function Node:getCascadeBoundingBox()
    local rc
    local func = tolua.getcfunction(self, "getCascadeBoundingBox")
    if func then
        rc = func(self)
    end

    rc.origin = {x=rc.x, y=rc.y}
    rc.size = {width=rc.width, height=rc.height}
    rc.containsPoint = isPointIn
    return rc
end

function Node:setAnchorPointX(apX)
    local ap = self:getAnchorPoint()
    if ap.x == apX then return end
    self:setAnchorPoint(cc.p(apX, ap.y))
end

--[[--

测试一个点是否在当前结点区域中

@param tabel point cc.p的点位置,世界坐标
@param boolean bCascade 是否用结点的所有子结点共同区域计算还是只用本身的区域

@return boolean 是否在结点区域中

]]
function Node:hitTest(pointX,pointY, bCascade)
    --by will 
    --getCascadeBoundingBox&getBoundingBox return world point ,so don't need convert point
    --local nsp = self:convertToNodeSpace(point)
    local rect
    if bCascade then
        rect = self:getCascadeBoundingBox()
    else
        rect = self:getBoundingBox()
    end

    if cc.rectContainsPoint(rect, {x=pointX,y=pointY}) then
        return true
    end
    return false
end

function Node:removeSelf()
    self:removeFromParent(true)
end


function Node:setBaseNodeEventListener()
    if self._baseNodeEventListener_ then return end
    self._baseNodeEventListener_ = function(evt)
            self:EventDispatcher(c.NODE_EVENT, evt)
    end
    self:registerScriptHandler(self._baseNodeEventListener_)
end


function Node:removeAllNodeEventListeners()
    self:disableNodeEvents()
end


function Node:setTouchSwallowEnabled(b)
    --do not use this . please use 'Widget' 'Layer' or 'Layout' to block touchs
    --print("==========>NodeEx setTouchSwallowEnabled: warnning please use Layer block touch. see LayerEx onTouch")
end

function Node:setNodeEventEnabled(b)
    if b then
        self:enableNodeEvents();
    else
        self:disableNodeEvents()
    end
end

function Node:onUpdate(callback,interval)
    if type(interval)=="number" then
        local updateFunc = function(dt) 
            self._updateTime = self._updateTime + dt
            if self._updateTime < interval then
                return 
            end
            callback(self._updateTime)
            self._updateTime = 0
        end
        self._updateTime = 0
        self:scheduleUpdateWithPriorityLua(updateFunc, 0)
    else
        self:scheduleUpdateWithPriorityLua(callback, 0)
    end
    
    return self
end

Node.scheduleUpdate = Node.onUpdate

function Node:onNodeEvent(eventName, callback)
    if "enter" == eventName then
        self.onEnterCallback_ = callback
    elseif "exit" == eventName then
        self.onExitCallback_ = callback
    elseif "enterTransitionFinish" == eventName then
        self.onEnterTransitionFinishCallback_ = callback
    elseif "exitTransitionStart" == eventName then
        self.onExitTransitionStartCallback_ = callback
    elseif "cleanup" == eventName then
        self.onCleanupCallback_ = callback
    end
    self:enableNodeEvents()
end

function Node:enableNodeEvents()
    if self.isNodeEventEnabled_ then
        return self
    end

    self:registerScriptHandler(function(state)
        if state == "enter" then
            self:onEnter_()
        elseif state == "exit" then
            self:onExit_()
        elseif state == "enterTransitionFinish" then
            self:onEnterTransitionFinish_()
        elseif state == "exitTransitionStart" then
            self:onExitTransitionStart_()
        elseif state == "cleanup" then
            self:onCleanup_()
        end
    end)
    self.isNodeEventEnabled_ = true

    return self
end

function Node:disableNodeEvents()
    self:unregisterScriptHandler()
    self.isNodeEventEnabled_ = false
    return self
end


function Node:onEnter()
end

function Node:onExit()
end

function Node:onEnterTransitionFinish()
end

function Node:onExitTransitionStart()
end

function Node:onCleanup()
end

function Node:onEnter_()
    self:onEnter()
    if not self.onEnterCallback_ then
        return
    end
    self:onEnterCallback_()
end

function Node:onExit_()
    self:onExit()
    if not self.onExitCallback_ then
        return
    end
    self:onExitCallback_()
end

function Node:onEnterTransitionFinish_()
    self:onEnterTransitionFinish()
    if not self.onEnterTransitionFinishCallback_ then
        return
    end
    self:onEnterTransitionFinishCallback_()
end

function Node:onExitTransitionStart_()
    self:onExitTransitionStart()
    if not self.onExitTransitionStartCallback_ then
        return
    end
    self:onExitTransitionStartCallback_()
end

function Node:onCleanup_()
    self:onCleanup()
    if not self.onCleanupCallback_ then
        return
    end
    self:onCleanupCallback_()
end

if not Node.findChild then
    function Node:findChild(name, isRecursive)
        if isRecursive then
            -- 递归查找
            name = "//" .. name
        end
        local child = nil
        self:enumerateChildren(name,function(node) 
            child=node 
            return true 
        end)
        return child
    end
end

local pauseFunc = Node.pause
local resumeFunc = Node.resume
function Node:pauseRecursive()
    pauseFunc(self)
    for _,child in pairs(self:getChildren()) do
        child:pauseRecursive()
    end
end

function Node:resumeRecursive()
    resumeFunc(self)
    for _,child in pairs(self:getChildren()) do
        child:resumeRecursive()
    end
end

function Node:request(message,data,cb,opts)
    app.session:request(message,data,function() 
        local isnull = tolua.isnull(self)
        if not isnull then
            if cb then
                cb()
            end
        end
    end,opts)
end

-- 加载csb时，自动加载附带的timeline，且默认设置tag=0，其他自己添加的action避免使用0
function Node:getTimeline()
    local actionTemp = self:getActionByTag( 0 )
    if not actionTemp then
        actionTemp = self:getActionByTag( self:getTag() )
    end
    return actionTemp
end




function Node:setAutoCleanupEnabled()
    local function onNodeEvent(event)
        if "cleanup" == event then
            if self.autoCleanupImages_ then
                for imageName, v in pairs(self.autoCleanupImages_) do
                    display.removeSpriteFrameByImageName(imageName)
                end
                self.autoCleanupImages_ = nil
            end
        end
    end
    self:registerScriptHandler(onNodeEvent)
end

function Node:markAutoCleanupImage(imageName)
    if not self.autoCleanupImages_ then self.autoCleanupImages_ = {} end
    self.autoCleanupImages_[imageName] = true
    return self
end
